package com.cictec.middleware.ribbon.loadbalancer.rule;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import com.cictec.middleware.commons.spring.SpringContextHolder;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

/**
 * 自定义 gps分析服务负载规则 目前只针对单独分发程序使用，如果是分发服务也是集群，需要重写
 * 
 * @author ql
 *
 */
public class MiddlewareDcRule extends AbstractLoadBalancerRule {
	
	private static Logger logger = LoggerFactory.getLogger(MiddlewareDcRule.class);

	/**
	 * 将相同cityCode 相同线路的设备放入同一个middleware-gps服务中处理
	 * 
	 * cityCode devLineId devCode
	 * 
	 * 
	 * private ConcurrentHashMap determineCurrentMap = new ConcurrentHashMap();
	 */

	/**
	 * 将相同cityCode 相同线路的设备放入同一个middleware-gps服务中处理
	 * 
	 * cityCode devLineId devCode
	 * 
	 * 
	 */
	private ConcurrentHashMap<String, Set<String>> determineCurrentMap = new ConcurrentHashMap<String, Set<String>>();

	
	
	private boolean isSameCityCode(Server server, String cityCode){
		String serverId = server.getId();
		
		boolean flag = false;
		DiscoveryClient discoveryClient = SpringContextHolder.getBean("discoveryClient");
		List<ServiceInstance> serviceList = discoveryClient.getInstances("middleware-dc");
		for (ServiceInstance serviceInstance : serviceList) {
			Map<String, String> metaData = serviceInstance.getMetadata();
			if(metaData.containsKey("cityCode")){
				String _serverId = serviceInstance.getHost() + ":" + serviceInstance.getPort();
				if(serverId.equals(_serverId)){
					
					logger.error("serverId: {} \t getServiceId: {} \t getHost: {} \t getPort: {} \t getUri: {} \t getMetadata: {} \t"
							, serverId
							, serviceInstance.getServiceId()
							, serviceInstance.getHost()
							, serviceInstance.getPort()
							, serviceInstance.getUri()
							, metaData
							);
					flag = true;
					break;
				}
			}

		}
		return flag;
	}
	
	/**
	 * 获取cityCode相同的服务
	 * @param lb
	 * @param key
	 * @return
	 */
	private List<Server> getServer(ILoadBalancer lb, Object key) {

		List<Server> list = new ArrayList<Server>();
		
		String cityCode = ThreadContextHolder.getCityCode();
//		System.out.println(cityCode);
		
		List<Server> upList = lb.getReachableServers();
		List<Server> allList = lb.getAllServers();

		
		if(upList.size() > 0){
			// 判定设备是否在维护的map中，没有新增
			for (Server _server : upList) {
				String serverId = _server.getId();
				if(!determineCurrentMap.containsKey(serverId)){
					Set<String> set = ConcurrentHashMap.<String> newKeySet();
					determineCurrentMap.put(serverId, set);
				}
			}
			
			for (Server _server : upList) {
				if(isSameCityCode(_server, cityCode)){
					list.add(_server);
				}
			}
		}
		
		return list;

	}

	private Random rand = new Random();


	public Server choose(ILoadBalancer lb, Object key) {
		
		
		if (lb == null) {
			return null;
		}
		Server server = null;

		while (server == null) {
			if (Thread.interrupted()) {
				return null;
			}
			List<Server> upList = lb.getReachableServers();
			List<Server> allList = lb.getAllServers();

			/**********************************/
			// 基于轮询规则下，重写获取服务
			upList = getServer(lb, key);
			allList = getServer(lb, key);
//			System.out.println("upList=" + upList);
//			System.out.println("allList=" + allList);
			/**********************************/
			
			int serverCount = allList.size();
			if (serverCount == 0) {
				/*
				 * No servers. End regardless of pass, because subsequent passes
				 * only get more restrictive.
				 */
				return null;
			}

			int index = rand.nextInt(serverCount);
			server = upList.get(index);

			if (server == null) {
				/*
				 * The only time this should happen is if the server list were
				 * somehow trimmed. This is a transient condition. Retry after
				 * yielding.
				 */
				Thread.yield();
				continue;
			}

			if (server.isAlive()) {
				return (server);
			}

			// Shouldn't actually happen.. but must be transient or a bug.
			server = null;
			Thread.yield();
		}

		return server;

	}

	@Override
	public Server choose(Object key) {
		// TODO Auto-generated method stub
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub

		System.out.println("ok");
	}

}
